package com.tcsa.openplatform.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Base64Utils;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 类名称：com.tcsa.openplatform.util.RSASignUtil
 * 类描述：RSA签名工具
 * 创建时间：2020/8/13 19:27
 *
 * @author：shane
 * @Mail: shanbaohua@tcsa.cloud
 */
@Slf4j
public class RSASignUtil {

    /**
     * 摘要加密算饭
     */
    private static String SIGN_ALGORITHMS = "SHA1WithRSA";

    private static final String ALGORITHM = "RSA";

    private static final String CHAR_SET = "UTF-8";

    private static final int RSA_KEY_SIZE = 1024;

    private static KeyFactory keyFactory = null;

    static {
        try {
            keyFactory = KeyFactory.getInstance(ALGORITHM);
        } catch (Exception e) {
            log.error("init key factory failed.", e);
        }
    }

    /**
     * 数据签名
     *
     * @param content    签名内容
     * @param privateKey 私钥
     * @return 返回签名数据
     */
    public static String sign(String content, String privateKey) {
        try {
            PrivateKey priKey = getPrivateKeyFromBase64KeyEncodeStr(privateKey);

            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);

            signature.initSign(priKey);
            signature.update(content.getBytes(CHAR_SET));

            byte[] signed = signature.sign();

            return Base64Utils.encodeToString(signed);
        } catch (Exception e) {
            log.error("sign failed.", e);
        }

        return null;
    }

    /**
     * 签名验证
     *
     * @param content
     * @param sign
     * @param publicKey
     * @return
     */
    public static boolean verify(String content, String sign, String publicKey) {
        try {
            PublicKey pubKey = getPublicKeyFromBase64KeyEncodeStr(publicKey);

            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(CHAR_SET));

            boolean verify = signature.verify(Base64Utils.decodeFromString(sign));
            return verify;

        } catch (Exception e) {
            log.error("verify failed.", e);
        }

        return false;
    }

    /**
     * 生成RSA密钥对
     *
     * @return
     */
    private static KeyPair generateKeyPair() {
        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
            keyPairGen.initialize(RSA_KEY_SIZE, new SecureRandom());
            KeyPair keyPair = keyPairGen.generateKeyPair();
            return keyPair;
        } catch (Exception e) {
            log.error("generateKeyPair failed.", e);
            return null;
        }
    }

    /**
     * Base64字符串的私钥转换为key对象
     *
     * @param keyStr
     * @return
     */
    private static PrivateKey getPrivateKeyFromBase64KeyEncodeStr(String keyStr) {
        byte[] keyBytes = Base64Utils.decodeFromString(keyStr);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey privateKey = null;
        try {
            privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        } catch (InvalidKeySpecException e) {
            log.error("getPrivateKeyFromBase64KeyEncodeStr [{}] failed. {}", keyStr, e.getMessage());
        }
        return privateKey;
    }

    public static RsaKey generate() throws Exception {
        KeyPair keyPair = generateKeyPair();
        String privateKey = Base64Utils.encodeToString(keyPair.getPrivate().getEncoded());
        String publicKey = Base64Utils.encodeToString(keyPair.getPublic().getEncoded());
        return RsaKey.init(privateKey, publicKey);
    }

    /**
     * Base64字符串的公钥转换为key对象
     *
     * @param keyStr
     * @return
     */
    private static PublicKey getPublicKeyFromBase64KeyEncodeStr(String keyStr) {
        byte[] keyBytes = Base64Utils.decodeFromString(keyStr);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        PublicKey publicKey = null;
        try {
            publicKey = keyFactory.generatePublic(x509KeySpec);
        } catch (Exception e) {
            log.error("getPublicKeyFromBase64KeyEncodeStr [{}] failed. {}", keyStr, e.getMessage());
        }
        return publicKey;
    }

    public static void main(String[] args) throws Exception {

        KeyPair keyPair = generateKeyPair();
        String privateKey = Base64Utils.encodeToString(keyPair.getPrivate().getEncoded());
        String publicKey = Base64Utils.encodeToString(keyPair.getPublic().getEncoded());

        String password = "Yxo#072zSzoN";

        String data = "{\"account\":\"zhang3\",\"name\":\"张三\"}";
        String aesSignedStr = AESUtil.encrypt2Str(data, password);
        System.out.println("AES加密-->" + aesSignedStr);

        String signed = sign(aesSignedStr, privateKey);
        System.out.println("加签-->" + signed);

        boolean signResult = verify(aesSignedStr, signed, publicKey);

        System.out.println("验签结果-->" + signResult);

        System.out.println("AES解密-->" + AESUtil.decrypt2Str(aesSignedStr, password));
    }

}
